详解QT中的快速正弦、快速余弦函数的实现 您所在的位置:网站首页 sin 正弦函数 详解QT中的快速正弦、快速余弦函数的实现

详解QT中的快速正弦、快速余弦函数的实现

2023-09-03 09:26| 来源: 网络整理| 查看: 265

文章目录 一、问题描述二、推导过程三、c代码

一、问题描述

  数值计算中,许多数学函数(如正弦、余弦、平方根等)可以通过泰勒级数展开的方法求得,然而,对于正弦函数与余弦函数,采用泰勒级数展开的方法收敛速度慢,计算速度慢。那么,有没有快速计算正弦函数与余弦函数并且可以估算误差限的算法呢?   QT中提供了快速正弦函数、快速余弦函数的算法,代码片段如下:

#define QT_SINE_TABLE_SIZE 256 #define M_PI (3.14159265358979323846) inline qreal qFastSin(qreal x) { int si = int(x * (0.5 * QT_SINE_TABLE_SIZE / M_PI)); // Would be more accurate with qRound, but slower. qreal d = x - si * (2.0 * M_PI / QT_SINE_TABLE_SIZE); int ci = si + QT_SINE_TABLE_SIZE / 4; si &= QT_SINE_TABLE_SIZE - 1; ci &= QT_SINE_TABLE_SIZE - 1; return qt_sine_table[si] + (qt_sine_table[ci] - 0.5 * qt_sine_table[si] * d) * d; } inline qreal qFastCos(qreal x) { int ci = int(x * (0.5 * QT_SINE_TABLE_SIZE / M_PI)); // Would be more accurate with qRound, but slower. qreal d = x - ci * (2.0 * M_PI / QT_SINE_TABLE_SIZE); int si = ci + QT_SINE_TABLE_SIZE / 4; si &= QT_SINE_TABLE_SIZE - 1; ci &= QT_SINE_TABLE_SIZE - 1; return qt_sine_table[si] - (qt_sine_table[ci] + 0.5 * qt_sine_table[si] * d) * d; } 二、推导过程

  QT中提供的快速正弦、快速余弦的算法,是一种典型的以空间换时间的查表法。这里以快速正弦函数为例进行讲解,对于快速余弦函数很容易类比推导得到。   由于 s i n ( x ) sin(x) sin(x)为周期为 2 π 2\pi 2π的函数,对于任意实数 x x x均可以变换到区间 [ 0 , 2 π ] [0,2\pi] [0,2π],假设区间 [ 0 , 2 π ] [0,2\pi] [0,2π]的正弦表 s i n e T a b l e sineTable sineTable长度为 N N N。   求 s i n ( x ) sin(x) sin(x)时,实数 x x x所对应的最接近其值的正弦表索引(不一定在 0 至 N − 1 0 至 N-1 0至N−1之间): s i = r o u n d ( x N 2 π ) (1) s_i=round(\dfrac{xN}{2\pi})\tag 1 si​=round(2πxN​)(1)   由于调用 r o u n d round round取整函数增加了函数调用的开销,这里用其他方式实现 r o u n d round round函数的功能。若 x > 0 x>0 x>0,则 s i g n = 1 sign=1 sign=1;否则, s i g n = − 1 sign=-1 sign=−1。计算 r o u n d ( x N 2 π ) round(\dfrac{xN}{2\pi}) round(2πxN​)等价于计算 ( i n t ) ( x N 2 π + s i g n ∗ 0.5 ) (int) (\dfrac{xN}{2\pi}+sign*0.5) (int)(2πxN​+sign∗0.5)。

  计算 x x x与所对应的最接近其值的正弦表横坐标 x s i x_{s_i} xsi​​的偏差: d = x − s i 2 π N (2) d=x-s_i \dfrac{2\pi}{N} \tag 2 d=x−si​N2π​(2)   由于 c o s ( x ) = s i n ( x + π / 2 ) cos(x)=sin(x+\pi/2) cos(x)=sin(x+π/2),因而,求 c o s ( x ) cos(x) cos(x)时,实数 x x x所对应的最接近其值的正弦表索引(不一定在 0 至 N − 1 0 至 N-1 0至N−1之间): c i = s i + N / 4 (3) c_i=s_i + N/4\tag 3 ci​=si​+N/4(3)   由于除法运算较慢,上式可以采用移位运算代替: c i = s i + ( N > > 2 ) c_i=s_i +( N>>2) ci​=si​+(N>>2)   将 s i , c i s_i,c_i si​,ci​变换到 0 至 N − 1 0至N-1 0至N−1之间: { s i = s i & ( N − 1 ) c i = c i & ( N − 1 ) (4) \begin{cases} s_i=s_i \& (N-1) \\ c_i=c_i \& (N-1) \\ \tag 4 \end{cases} {si​=si​&(N−1)ci​=ci​&(N−1)​(4)   其中, & \& &表示按位与。   由于 s i n ( x ) = s i n ( x s i + d ) = s i n ( x s i ) c o s ( d ) + c o s ( x s i ) s i n ( d ) sin(x)=sin(x_{s_i}+d)=sin(x_{s_i})cos(d)+cos(x_{s_i})sin(d) sin(x)=sin(xsi​​+d)=sin(xsi​​)cos(d)+cos(xsi​​)sin(d), d d d很小, s i n ( d ) , c o s ( d ) sin(d),cos(d) sin(d),cos(d)用等价无穷小代替: { s i n ( d ) ∼ d c o s ( d ) ∼ 1 − d 2 / 2 (5) \begin{cases} sin(d) \sim d \\ cos(d)\sim1-d^2/2 \\ \tag 5 \end{cases} {sin(d)∼dcos(d)∼1−d2/2​(5)   得到: s i n ( x ) = s i n e T a b l e [ s i ] + ( s i n e T a b l e [ c i ] − 0.5 ∗ s i n e T a b l e [ s i ] ∗ d ) ∗ d (6) sin(x)=sineTable[s_i] +(sineTable[c_i] - 0.5*sineTable[s_i]*d) *d \tag 6 sin(x)=sineTable[si​]+(sineTable[ci​]−0.5∗sineTable[si​]∗d)∗d(6)   特别的,当需要同时计算 s i n ( x ) , c o s ( x ) sin(x),cos(x) sin(x),cos(x)时,为了进一步减小计算量,避免重复计算 d , s s , c i d,s_s,c_i d,ss​,ci​,可以将计算 s i n ( x ) , c o s ( x ) sin(x),cos(x) sin(x),cos(x)写成一个函数。    s i n ( x ) sin(x) sin(x)在 0 0 0处的泰勒展开为: s i n ( x ) = x − x 3 / 6 + x 5 / 120 − x 7 / 5040 + . . . sin(x)=x-x^3/6 + x^5/120- x^7/5040+... sin(x)=x−x3/6+x5/120−x7/5040+...。    c o s ( x ) cos(x) cos(x)在 0 0 0处的泰勒展开为: c o s ( x ) = 1 − x 2 / 2 + x 4 / 24 − x 6 / 720 + . . . cos(x)=1- x^2/2 + x^4/24- x^6/720+... cos(x)=1−x2/2+x4/24−x6/720+...。   采用式(5)的等价无穷小表示时, s i n ( d ) sin(d) sin(d)的误差限约为 ϵ s = d m a x 3 / 6 \epsilon_{s}=d_{max}^3/6 ϵs​=dmax3​/6, c o s ( d ) cos(d) cos(d)的误差限约为 ϵ c = d m a x 4 / 24 \epsilon_{c}=d_{max}^4/24 ϵc​=dmax4​/24, d m a x = π / ( N − 1 ) d_{max}=\pi/(N-1) dmax​=π/(N−1)。   计算 s i n ( x ) sin(x) sin(x)的误差限: ϵ s i n e ≤ ∣ s i n ( x s i ) ∣ m a x ∗ ϵ c + ∣ c o s ( x s i ) ∣ m a x ∗ ϵ s = ϵ c + ϵ s (7) \epsilon_{sine}\le |sin(x_{s_i})|_{max} * \epsilon_{c} + |cos(x_{s_i})|_{max} * \epsilon_{s}=\epsilon_{c}+\epsilon_{s} \tag 7 ϵsine​≤∣sin(xsi​​)∣max​∗ϵc​+∣cos(xsi​​)∣max​∗ϵs​=ϵc​+ϵs​(7)

  同理可计算 c o s ( x ) cos(x) cos(x)的误差限: ϵ c o s i n e ≤ ϵ c + ϵ s (8) \epsilon_{cosine}\le \epsilon_{c}+\epsilon_{s} \tag 8 ϵcosine​≤ϵc​+ϵs​(8)   

三、c代码

  快速正弦函数、快速余弦函数的c语言实现如下:

#define SINE_TABLE_SIZE 256 static const double sineTable[SINE_TABLE_SIZE] = { 0.0, 0.024541228522912288, 0.049067674327418015, 0.073564563599667426, 0.098017140329560604, 0.1224106751992162, 0.14673047445536175, 0.17096188876030122, 0.19509032201612825, 0.2191012401568698, 0.24298017990326387, 0.26671275747489837, 0.29028467725446233, 0.31368174039889152, 0.33688985339222005, 0.35989503653498811, 0.38268343236508978, 0.40524131400498986, 0.42755509343028208, 0.44961132965460654, 0.47139673682599764, 0.49289819222978404, 0.51410274419322166, 0.53499761988709715, 0.55557023301960218, 0.57580819141784534, 0.59569930449243336, 0.61523159058062682, 0.63439328416364549, 0.65317284295377676, 0.67155895484701833, 0.68954054473706683, 0.70710678118654746, 0.72424708295146689, 0.74095112535495911, 0.75720884650648446, 0.77301045336273699, 0.78834642762660623, 0.80320753148064483, 0.81758481315158371, 0.83146961230254524, 0.84485356524970701, 0.85772861000027212, 0.87008699110871135, 0.88192126434835494, 0.89322430119551532, 0.90398929312344334, 0.91420975570353069, 0.92387953251128674, 0.93299279883473885, 0.94154406518302081, 0.94952818059303667, 0.95694033573220894, 0.96377606579543984, 0.97003125319454397, 0.97570213003852857, 0.98078528040323043, 0.98527764238894122, 0.98917650996478101, 0.99247953459870997, 0.99518472667219682, 0.99729045667869021, 0.99879545620517241, 0.99969881869620425, 1.0, 0.99969881869620425, 0.99879545620517241, 0.99729045667869021, 0.99518472667219693, 0.99247953459870997, 0.98917650996478101, 0.98527764238894122, 0.98078528040323043, 0.97570213003852857, 0.97003125319454397, 0.96377606579543984, 0.95694033573220894, 0.94952818059303667, 0.94154406518302081, 0.93299279883473885, 0.92387953251128674, 0.91420975570353069, 0.90398929312344345, 0.89322430119551521, 0.88192126434835505, 0.87008699110871146, 0.85772861000027212, 0.84485356524970723, 0.83146961230254546, 0.81758481315158371, 0.80320753148064494, 0.78834642762660634, 0.7730104533627371, 0.75720884650648468, 0.74095112535495899, 0.72424708295146689, 0.70710678118654757, 0.68954054473706705, 0.67155895484701855, 0.65317284295377664, 0.63439328416364549, 0.61523159058062693, 0.59569930449243347, 0.57580819141784545, 0.55557023301960218, 0.53499761988709715, 0.51410274419322177, 0.49289819222978415, 0.47139673682599786, 0.44961132965460687, 0.42755509343028203, 0.40524131400498992, 0.38268343236508989, 0.35989503653498833, 0.33688985339222033, 0.31368174039889141, 0.29028467725446239, 0.26671275747489848, 0.24298017990326407, 0.21910124015687005, 0.19509032201612861, 0.17096188876030122, 0.1467304744553618, 0.12241067519921635, 0.098017140329560826, 0.073564563599667732, 0.049067674327417966, 0.024541228522912326, 0.0, -0.02454122852291208, -0.049067674327417724, -0.073564563599667496, -0.09801714032956059, -0.1224106751992161, -0.14673047445536158, -0.17096188876030097, -0.19509032201612836, -0.2191012401568698, -0.24298017990326382, -0.26671275747489825, -0.29028467725446211, -0.31368174039889118, -0.33688985339222011, -0.35989503653498811, -0.38268343236508967, -0.40524131400498969, -0.42755509343028181, -0.44961132965460665, -0.47139673682599764, -0.49289819222978393, -0.51410274419322155, -0.53499761988709693, -0.55557023301960196, -0.57580819141784534, -0.59569930449243325, -0.61523159058062671, -0.63439328416364527, -0.65317284295377653, -0.67155895484701844, -0.68954054473706683, -0.70710678118654746, -0.72424708295146678, -0.74095112535495888, -0.75720884650648423, -0.77301045336273666, -0.78834642762660589, -0.80320753148064505, -0.81758481315158382, -0.83146961230254524, -0.84485356524970701, -0.85772861000027201, -0.87008699110871135, -0.88192126434835494, -0.89322430119551521, -0.90398929312344312, -0.91420975570353047, -0.92387953251128652, -0.93299279883473896, -0.94154406518302081, -0.94952818059303667, -0.95694033573220882, -0.96377606579543984, -0.97003125319454397, -0.97570213003852846, -0.98078528040323032, -0.98527764238894111, -0.9891765099647809, -0.99247953459871008, -0.99518472667219693, -0.99729045667869021, -0.99879545620517241, -0.99969881869620425, -1.0, -0.99969881869620425, -0.99879545620517241, -0.99729045667869021, -0.99518472667219693, -0.99247953459871008, -0.9891765099647809, -0.98527764238894122, -0.98078528040323043, -0.97570213003852857, -0.97003125319454397, -0.96377606579543995, -0.95694033573220894, -0.94952818059303679, -0.94154406518302092, -0.93299279883473907, -0.92387953251128663, -0.91420975570353058, -0.90398929312344334, -0.89322430119551532, -0.88192126434835505, -0.87008699110871146, -0.85772861000027223, -0.84485356524970723, -0.83146961230254546, -0.81758481315158404, -0.80320753148064528, -0.78834642762660612, -0.77301045336273688, -0.75720884650648457, -0.74095112535495911, -0.724247082951467, -0.70710678118654768, -0.68954054473706716, -0.67155895484701866, -0.65317284295377709, -0.63439328416364593, -0.61523159058062737, -0.59569930449243325, -0.57580819141784523, -0.55557023301960218, -0.53499761988709726, -0.51410274419322188, -0.49289819222978426, -0.47139673682599792, -0.44961132965460698, -0.42755509343028253, -0.40524131400499042, -0.38268343236509039, -0.359895036534988, -0.33688985339222, -0.31368174039889152, -0.2902846772544625, -0.26671275747489859, -0.24298017990326418, -0.21910124015687016, -0.19509032201612872, -0.17096188876030177, -0.14673047445536239, -0.12241067519921603, -0.098017140329560506, -0.073564563599667412, -0.049067674327418091, -0.024541228522912448 }; /********************************************************************************************** Function: fast_sin Description: 快速正弦函数 Input: 浮点数x Output: 无 Input_Output: 无 Return: sin(x) Author: Marc Pony([email protected]) ***********************************************************************************************/ double fast_sin(double x) { int sign = x > 0.0 ? 1 : -1; int si = (int)(x * SINE_TABLE_SIZE / (2.0 * PI) + sign * 0.5); //+0.5后取整等价于round函数 double d = x - si * (2.0 * PI / SINE_TABLE_SIZE); int ci = si + (SINE_TABLE_SIZE >> 2); si &= (SINE_TABLE_SIZE - 1); ci &= (SINE_TABLE_SIZE - 1); return sineTable[si] + (sineTable[ci] - 0.5 * sineTable[si] * d) * d; } /********************************************************************************************** Function: fast_cos Description: 快速余弦函数 Input: 浮点数x Output: 无 Input_Output: 无 Return: cos(x) Author: Marc Pony([email protected]) ***********************************************************************************************/ double fast_cos(double x) { int sign = x > 0.0 ? 1 : -1; int ci = (int)(x * SINE_TABLE_SIZE / (2.0 * PI) + sign * 0.5); //+0.5后取整等价于round函数 double d = x - ci * (2.0 * PI / SINE_TABLE_SIZE); int si = ci + (SINE_TABLE_SIZE >> 2); si &= (SINE_TABLE_SIZE - 1); ci &= (SINE_TABLE_SIZE - 1); return sineTable[si] - (sineTable[ci] + 0.5 * sineTable[si] * d) * d; } /********************************************************************************************** Function: fast_sin_cos Description: 快速正弦函数和快速余弦函数同时计算 Input: 浮点数x Output: 正弦值sinX,余弦值cosX Input_Output: 无 Return: 无 Author: Marc Pony([email protected]) ***********************************************************************************************/ void fast_sin_cos(double x, double* sinX, double* cosX) { int sign = x > 0.0 ? 1 : -1; int si = (int)(x * SINE_TABLE_SIZE / (2.0 * PI) + sign * 0.5); //+0.5后取整等价于round函数 double d = x - si * (2.0 * PI / SINE_TABLE_SIZE); int ci = si + (SINE_TABLE_SIZE >> 2); si &= (SINE_TABLE_SIZE - 1); ci &= (SINE_TABLE_SIZE - 1); *sinX = sineTable[si] + (sineTable[ci] - 0.5 * sineTable[si] * d) * d; *cosX = sineTable[ci] - (sineTable[si] + 0.5 * sineTable[ci] * d) * d; } #define _CRT_SECURE_NO_WARNINGS #include #include #include #define TEST_COUNT 10000000 int main() { int i, N[3]; long startTime, finishTime; double deltaX, maxErrorSine, maxErrorCosine; double dmax, epsilon, x, s1, c1, s2, c2; startTime = clock(); for (i = 0; i fast_sin_cos(i, &s2, &c2); } finishTime = clock(); printf("优化后计算时间: %f s\n", (finishTime - startTime) / 1000.0); maxErrorSine = 0.0; maxErrorCosine = 0.0; deltaX = 2.0 * PI / (TEST_COUNT - 1); for (i = 0; i maxErrorSine = fabs(s1 - s2); } if (fabs(c1 - c2) > maxErrorCosine) { maxErrorCosine = fabs(c1 - c2); } } printf("快速正弦函数最大计算误差: %e\n", maxErrorSine); printf("快速余弦函数最大计算误差: %e\n", maxErrorCosine); N[0] = 256; N[1] = 512; N[2] = 1024; for (i = 0; i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有